@file:Suppress("SpringJavaInjectionPointsAutowiringInspection", "ReactiveStreamsUnusedPublisher", "unused", "SpringJavaAutowiredMembersInspection")

package com.sqi.reactive.common.controller

import com.sqi.reactive.common.annoation.IgnoreAuth
import com.sqi.reactive.common.result.PageResult
import com.sqi.reactive.common.service.BaseService
import io.swagger.annotations.ApiOperation
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.beans.factory.annotation.Value
import org.springframework.data.domain.PageRequest
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.RequestParam
import org.springframework.web.bind.annotation.ResponseBody
import reactor.core.publisher.Flux
import reactor.core.publisher.Mono
import java.io.Serializable

/**
 * @author sjl
 * @date 2020/6/1
 */
@Suppress("SpringJavaAutowiredMembersInspection")
abstract class BaseQueryController<T : Any, ID : Serializable, SERVICE : BaseService<T, *, ID>> {
    @Autowired
    protected lateinit var service: SERVICE
    protected var log: Logger = LoggerFactory.getLogger(this.javaClass)

    @Value("\${sqi.metaInfo:false}")
    protected lateinit var metaInfo: String

    @ApiOperation(value = "获取对象属性字段", notes = "此接口生产环境关闭")
    @GetMapping("/meta_info")
    @ResponseBody
    @IgnoreAuth
    fun metaInfo(): Mono<Map<String, Class<*>>> =
        if (metaInfo != "false") {
            this.service.metaInfo()
        } else {
            Mono.empty()
        }

    @ApiOperation(value = "根据主键查询", notes = "此接口为rest风格接口")
    @GetMapping("/get/{id}")
    @ResponseBody
    fun findById(@PathVariable id: ID): Mono<ResultHandler<T>> = resultHandler { doFindById(id) }

    open fun doFindById(id: ID): Mono<T> = this.service.findById(id)

    @ApiOperation(value = "查询所有数据", notes = "此接口为通用接口，查询方式参考通用接口使用说明")
    @GetMapping("/query_list")
    @ResponseBody
    fun queryAll(@RequestParam param: MutableMap<String, Any>): Mono<ResultHandler<List<T>>> =
            resultHandler { doQueryAll(param).collectList() }

    open fun doQueryAll(param: MutableMap<String, Any>): Flux<T> = this.service.findAll(param.wrap())

    abstract fun MutableMap<String, Any>.wrap(): MutableMap<String, Any>

    @ApiOperation(value = "分页查询", notes = "此接口为通用接口，查询方式参考通用接口使用说明")
    @GetMapping("/query_page")
    @ResponseBody
    fun queryPage(@RequestParam param: MutableMap<String, Any>,
                  @RequestParam(name = "page", defaultValue = "1") page: Int,
                  @RequestParam(name = "size", defaultValue = "20") size: Int): Mono<ResultHandler<PageResult<T>>> =
            resultHandler { this.doQueryPage(param, page, size) }


    open fun doQueryPage(param: MutableMap<String, Any>, page: Int, size: Int): Mono<PageResult<T>> =
            this.service.findAll(param.wrap(), PageRequest.of(page - 1, size))
}

fun <T> resultHandler(block: () -> Mono<T>): Mono<ResultHandler<T>> {
    return try {
        block().map { ResultHandler(data = it) }
            .defaultIfEmpty(ResultHandler(ResultHandler.ResultHandlerType.SUCCESS))
            .onErrorMap {
                it.printStackTrace()
                it
            }.onErrorResume {
                Mono.just(
                    ResultHandler(
                        code = ResultHandler.ResultHandlerType.SYSTEM_ERROR.code,
                        message = it.message
                    )
                )
            }
    } catch (e: Exception) {
        Mono.just(ResultHandler(code = ResultHandler.ResultHandlerType.SYSTEM_ERROR.code,
                message = e.message))
    }
}

fun <T> resultHandler(any: T?): Mono<ResultHandler<T?>> {
    return resultHandler { Mono.justOrEmpty(any) }
}